package consumer

import (
	"context"
	"encoding/json"
	"fmt"
	"new_for_deepseek_rabbitmq/config"
	"new_for_deepseek_rabbitmq/logger"
	"new_for_deepseek_rabbitmq/model"
	"new_for_deepseek_rabbitmq/model/drafts"
	rabbitmqProject "new_for_deepseek_rabbitmq/project/rabbitmq"
	"new_for_deepseek_rabbitmq/project/tencent/lke/event"
	"new_for_deepseek_rabbitmq/project/tencent/lke/sse"
	"strings"
	"sync"
	"time"

	tencentlke "new_for_deepseek_rabbitmq/project/tencent/lke"

	"github.com/google/uuid"
	"github.com/streadway/amqp"
	"gorm.io/gorm"
)

type NewsConsumerStruct struct {
	sync.Mutex     // 添加互斥锁
	questionAnswer *model.QuestionAnswerModel
	KeepTitle      int
	KeepContent    int
	logId          int
}

func NewsConsumer() *NewsConsumerStruct {
	return &NewsConsumerStruct{}
}

// 定义新的结构体类型
type newsConsumerWithLog struct {
	*NewsConsumerStruct
	logId int
}

// 入口方法
func (n *NewsConsumerStruct) Start() (err error) {

	ch, err := rabbitmqProject.GetChannel()
	if err != nil {
		logger.Error("获取RabbitMQ通道失败: %s", err.Error())
		return
	}
	defer rabbitmqProject.ReleaseChannel(ch)

	// 使用工具函数声明交换机和队列
	if err = rabbitmqProject.DeclareExchangeAndQueue(ch, rabbitmqProject.NewsConfig); err != nil {
		logger.Error("初始化RabbitMQ失败: %s", err.Error())
		return
	}

	// 消费消息
	msgs, err := ch.Consume(
		rabbitmqProject.NewsConfig.QueueName,
		"",
		false,
		false,
		false,
		false,
		nil,
	)
	if err != nil {
		logger.Error("设置消费者失败: %s", err.Error())
		return
	}

	// 发布
	tencentlke.Release()

	// 循环消费消息
	for msg := range msgs {
		// 解析消息，获取 logId
		var newsMessage rabbitmqProject.NewsMessage
		if err := json.Unmarshal(msg.Body, &newsMessage); err != nil {
			logger.Error("解析消息失败: %s", err.Error())
			msg.Nack(false, false)
			continue
		}

		// 同步处理消息
		if err := n.processNews(msg); err != nil {
			msg.Nack(false, false)
		} else {
			msg.Ack(false)
		}
	}

	return nil
}

// 处理新闻流程
func (n *NewsConsumerStruct) processNews(msg amqp.Delivery) error {
	var newsMessage rabbitmqProject.NewsMessage
	if err := json.Unmarshal(msg.Body, &newsMessage); err != nil {
		logger.Error("Failed to unmarshal message body: %s, raw message: %s", err.Error(), string(msg.Body))
		return err
	}

	// 保存 logId
	originalLogId := newsMessage.LogId

	//更新状态
	model.GetInstance().DB.Model(&drafts.DraftsLogsModel{}).Where("id = ?", originalLogId).Update("status", 1)

	n.KeepTitle = newsMessage.KeepTitle
	n.KeepContent = newsMessage.KeepContent

	var wg sync.WaitGroup
	for _, id := range newsMessage.Ids {
		wg.Add(1)
		go func(id int, logId int) { // 传入 logId
			defer wg.Done()
			n.processOneNews(id, logId) // 传入 logId
		}(id, originalLogId) // 传入保存的 originalLogId
	}

	// 等待所有 goroutine 完成
	wg.Wait()

	// 所有新闻处理完成后，更新状态
	if err := model.GetInstance().DB.Model(&drafts.DraftsLogsModel{}).Where("id = ?", originalLogId).Updates(map[string]interface{}{
		"status":     2,
		"updated_at": time.Now(),
	}).Error; err != nil {
		logger.Error("更新状态失败: %s", err.Error())
	}

	return nil
}

// 处理单个新闻
func (n *NewsConsumerStruct) processOneNews(id int, logId int) {
	consumer := &newsConsumerWithLog{
		NewsConsumerStruct: n,
		logId:              logId,
	}

	db := model.GetInstance().DB

	// 初始化问题答案
	questionAnswer := &model.QuestionAnswerModel{}
	if err := db.Where("id = ?", id).First(questionAnswer).Error; err != nil {
		logger.Error("获取知识库失败, id: %d, err: %s", id, err.Error())
		consumer.incrementErrorNum(err.Error())
		return
	}

	var configModel model.ConfigModel
	if err := db.Where("`key` = 'template'").First(&configModel).Error; err != nil {
		logger.Error("获取配置信息失败, id: %d, err: %s", id, err.Error())
		consumer.incrementErrorNum(err.Error())
		return
	}

	//模板替换
	template := strings.Replace(configModel.Value, "${question}", questionAnswer.Question, -1)
	template = strings.Replace(template, "${answer}", questionAnswer.Answer, -1)
	template = template + ",请按照以下格式返回：<标题开始>标题</标题结束><文章seo描述开始>文章描述</文章seo描述结束><文章seo关键字开始>文章关键字</文章seo关键字结束><简介开始>正文</简介结束>。正文需使用富文本格式，禁止使用[]引用，#标志位中间不要有空格"

	// 是否保留标题
	if n.KeepTitle == 2 {
		template += "并以" + questionAnswer.Question + "为标题"
	}

	// 是否保留正文
	if n.KeepContent == 2 {
		template += "并以" + questionAnswer.Answer + "为正文"
	}

	ctx := context.TODO()
	option := sse.WithConnEndpoint(config.DefaultConfig.Tencent.Lke.ChatSeeUrl)

	replyCallback := func(ev event.EventWrapper) {
		reply := event.ReplyEvent{}
		if err := json.Unmarshal(ev.Payload, &reply); err != nil {
			logger.Error("解析回复失败: %v", err)
			consumer.incrementErrorNum(err.Error())
			return
		}

		// fmt.Println(reply.Content)

		if reply.IsFinal == true && reply.IsFromSelf == false {
			logger.Info("收到原始返回数据: %s", string(ev.Payload))

			title := extractContent(reply.Content, "<标题开始>", "</标题结束>")
			seoDesc := extractContent(reply.Content, "<文章seo描述开始>", "</文章seo描述结束>")
			seoKeyword := extractContent(reply.Content, "<文章seo关键字开始>", "</文章seo关键字结束>")
			content := extractContent(reply.Content, "<简介开始>", "</简介结束>")

			// 生成正文
			textTemplate := fmt.Sprintf(`请根据以下标题和描述，生成一篇专业文章。

标题：%s
描述：%s

要求：
1. 内容要求：
   - 5-8个核心内容点，每点300-500字
   - 逻辑清晰，层次分明
   - 紧扣主题，避免偏离
   - 避免重复和冗余

2. 格式规范：
   - 标题使用<h3>标签
   - 正文段落使用<p>标签
   - 重要内容用<strong>加粗
   - 专业术语用<em>强调
   - 禁止使用[]和Markdown格式
   - 简介部分禁止使用p标签

3. 写作要求：
   - 专业客观，避免营销化
   - 简洁明了，通俗易懂
   - 多用案例，少用概念
   - 确保真实，避免夸大

4. 文章结构：
   - 内容摘要：概述核心内容
   - 正文主体：5-8个内容点
   - 结论总结：核心观点总结
   - 常见问题：解答读者疑问

5. 质量要求：
   - 内容深入，避免浅显
   - 实用性强，可操作
   - 数据支持，案例佐证
   - 保持连贯，结构完整`, title, seoDesc)

			logger.Info("开始生成正文，模板: %s", textTemplate)

			// 创建新的context和client用于生成正文
			textCtx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
			defer cancel()

			textClient := sse.NewClient(option)
			var text string
			textDone := make(chan bool, 1)
			textErrChan := make(chan error, 1)

			textClient.On(event.EventReply, func(textEv event.EventWrapper) {
				logger.Info("正文生成收到返回: %s", string(textEv.Payload))

				var textReply event.ReplyEvent
				if err := json.Unmarshal(textEv.Payload, &textReply); err != nil {
					logger.Error("解析正文返回失败: %v", err)
					textErrChan <- err
					return
				}

				if textReply.IsFinal && !textReply.IsFromSelf {
					text = textReply.Content
					textDone <- true
				}
			})

			// 发送正文生成请求
			if err := textClient.Send(textCtx, &event.SseSendEvent{
				Content:      textTemplate,
				BotAppKey:    config.DefaultConfig.Tencent.Lke.BotAppKey,
				VisitorBizID: "",
				SessionID:    uuid.NewString(),
			}); err != nil {
				logger.Error("发送正文生成请求失败: %v", err)
				consumer.incrementErrorNum(err.Error())
				return
			}

			// 等待正文生成完成或超时
			select {
			case <-textDone:
				logger.Info("正文生成完成: %s", text)
			case err := <-textErrChan:
				logger.Error("正文生成失败: %v", err)
				consumer.incrementErrorNum(err.Error())
				return
			case <-textCtx.Done():
				logger.Error("正文生成超时")
				consumer.incrementErrorNum("正文生成超时")
				return
			}

			if n.KeepTitle == 2 {
				title = questionAnswer.Question
			}

			if n.KeepContent == 2 {
				content = questionAnswer.Answer
			}

			// 创建新闻
			if err := model.GetInstance().DB.Model(&model.NewsModel{}).
				Create(map[string]interface{}{
					"type_classify_id":     questionAnswer.TypeClassifyId,
					"business_classify_id": questionAnswer.BusinessClassifyId,
					"drafts_logs_id":       logId,
					"title":                title,
					"seo_desc":             seoDesc,
					"seo_keyword":          seoKeyword,
					"content":              content,
					"text":                 text,
					"question_answer_id":   questionAnswer.Id,
					"created_at":           time.Now(),
					"updated_at":           time.Now(),
				}).Error; err != nil {
				logger.Error("新闻入库失败: %v", err)
				consumer.incrementErrorNum(err.Error())
				return
			}

			logger.Info("新闻入库成功 - ID: %d", questionAnswer.Id)

			//判断是最后一条 回到初始状态
			startId := id + 1
			var questionAnswerModel model.QuestionAnswerModel
			model.GetInstance().DB.Model(&model.QuestionAnswerModel{}).Where("id = ?", questionAnswer.Id).Order("id DESC").First(&questionAnswerModel)
			if startId > questionAnswerModel.Id {
				startId = 0
			}

			model.GetInstance().DB.Model(&drafts.DraftsConfigModel{}).
				Where("id = ?", 1).Update("start_id", startId)

			consumer.incrementSuccessNum()
		}
	}

	c := sse.NewClient(option)
	c.On(event.EventReply, replyCallback)
	c.Send(ctx, &event.SseSendEvent{
		Content:      template,
		BotAppKey:    config.DefaultConfig.Tencent.Lke.BotAppKey,
		VisitorBizID: "",
		SessionID:    uuid.NewString(),
	})

	return
}

// 添加辅助函数来提取内容
func extractContent(content string, startMarker string, endMarker string) string {
	startIndex := strings.Index(content, startMarker)
	if startIndex == -1 {
		return ""
	}
	startIndex += len(startMarker)

	endIndex := strings.Index(content[startIndex:], endMarker)
	if endIndex == -1 {
		return ""
	}

	extracted := strings.TrimSpace(content[startIndex : startIndex+endIndex])
	// 移除每行开头的注释标记
	lines := strings.Split(extracted, "\n")
	var cleanLines []string
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if strings.HasPrefix(line, "// ") {
			line = strings.TrimPrefix(line, "// ")
		}
		if line != "" {
			cleanLines = append(cleanLines, line)
		}
	}
	return strings.Join(cleanLines, "\n")
}

// 修改 incrementErrorNum 方法
func (c *newsConsumerWithLog) incrementErrorNum(errorMsg string) {
	db := model.GetInstance().DB
	if err := db.Model(&drafts.DraftsLogsModel{}).Where("id = ?", c.logId).UpdateColumn("error_num", gorm.Expr("error_num + 1")).Error; err != nil {
		logger.Error("增加错误数量失败: %s", err.Error())
	}
	//增加错误信息
	if err := db.Model(&drafts.DraftsLogsErrorModel{}).Create(map[string]interface{}{
		"drafts_logs_id": c.logId,
		"error_msg":      errorMsg,
		"created_at":     time.Now(),
		"updated_at":     time.Now(),
	}).Error; err != nil {
		logger.Error("记录错误信息失败: %s", err.Error())
	}
}

// 修改 incrementSuccessNum 方法
func (c *newsConsumerWithLog) incrementSuccessNum() {
	db := model.GetInstance().DB
	if err := db.Model(&drafts.DraftsLogsModel{}).Where("id = ?", c.logId).UpdateColumn("success_num", gorm.Expr("success_num + 1")).Error; err != nil {
		logger.Error("增加成功数量失败: %s", err.Error())
	}
}
